/*
 * JVM_OpcodeFields.c
 *
 *  Created on: 05.01.2011
 *      Author: Tavin
 */


#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include "JVM_StatusCodes.h"
#include "JVM_DataTypes.h"
#include "JVM_Class.h"

#include "JVM_Opcode.h"
#include "JVM_OpcodeFields.h"
#include "JVM_Handle.h"
#include "JVM_StackFrame.h"


/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_putstatic							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.5			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_resolveFieldInfo(JVM_CP_Table_t * currentCpTable, JVM_CP_Field_t ** myFieldInfo, uint16_t index )
{

	uint8_t constantType;


	constantType=JVM_CPTable_getCpType(currentCpTable,index);

	if (!constantType==CONSTANT_TYPE_FIELD_REF)
		return (STCD_MISSING_FIELD_REFERENCE);

	*myFieldInfo=(JVM_CP_Field_t*)JVM_CPTable_getFieldInfo(currentCpTable,index);

	if (myFieldInfo==NULL)
			return (STCD_MISSING_FIELD_REFERENCE);


	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_getstatic							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.5			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_getstatic()
{
	JVM_StackFrame_t * myStackFrame;

	uint8_t fieldType;
	uint16_t index;
	JVM_CP_Field_t * myFieldInfo;


	union data_value myValue;


	int16_t returnValue;
	JVM_Class_t *myClass;
	JVM_Field_t *myField;
	JVM_HandleNumber_t handleNumber;
	uint16_t dataOffset;


	index=JVM_Opcode_getCodeShort();

	myStackFrame=JVM_Opcode_getActiveStackFrame();

	returnValue=JVM_resolveFieldInfo(myStackFrame->currentCpTable,&myFieldInfo,index);
	if (returnValue!=STCD_OK)
		return(returnValue);


	myClass=myFieldInfo->classAddress;
	myField=myFieldInfo->fieldAddress;

	dataOffset=myField->dataOffset;
	handleNumber=myClass->staticDataHandle;

	fieldType=myField->fieldType;
	//TODO Check Type (fieldinfo_t <-> Field_t!!!
	// TODO check if static

	uint16_t statusCode;

	switch(fieldType)
		{
		case FIELD_TYPE_BYTE:
		case FIELD_TYPE_BOOLEAN:
			statusCode=JVM_Handle_staticGetByte(handleNumber,dataOffset,&myValue.byteValue);
				if(statusCode!=STCD_OK)
						return(statusCode);
			break;


		case FIELD_TYPE_CHAR:
			statusCode=JVM_Handle_staticGetChar(handleNumber,dataOffset,&myValue.charValue);
				if(statusCode!=STCD_OK)
						return(statusCode);
			break;

		case FIELD_TYPE_SHORT:
			statusCode=JVM_Handle_staticGetShort(handleNumber,dataOffset,&myValue.shortValue);
				if(statusCode!=STCD_OK)
						return(statusCode);
			break;


		case FIELD_TYPE_INT:
			JVM_Handle_staticGetInt(handleNumber,dataOffset,&myValue.intValue);
			break;

		case FIELD_TYPE_ARRAY_REFERENCE:
		case FIELD_TYPE_CLASS_REFERENCE:
			JVM_Handle_staticGetReference(handleNumber,dataOffset,&myValue.reference);
			break;



		case FIELD_TYPE_FLOAT:
			JVM_Handle_staticGetFloat(handleNumber,dataOffset,&myValue.floatValue);
			break;


		case FIELD_TYPE_LONG:
			JVM_Handle_staticGetLong(handleNumber,dataOffset,&myValue.longValue);
			break;

		case FIELD_TYPE_DOUBLE:
			JVM_Handle_staticGetDouble(handleNumber,dataOffset,&myValue.doubleValue);
			break;


		default:
			return(STCD_UNKNOWN_FIELD_TYPE);
		}



	return(JVM_Opcode_pushFieldValue(fieldType,myValue));
}


/****************************************************************************************/
/*																						*/
/*	Function : JVM_Opcode_pushFieldValue					Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.5			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_Opcode_pushFieldValue(uint8_t fieldType, union data_value myValue)
{
	JVM_StackFrame_t * myStackFrame;
	myStackFrame=JVM_Opcode_getActiveStackFrame();

	switch(fieldType)
		{
		case FIELD_TYPE_BYTE:
		case FIELD_TYPE_BOOLEAN:
			JVM_StackFrame_pushIntValue(myStackFrame,myValue.byteValue);
			break;

		case FIELD_TYPE_CHAR:
			JVM_StackFrame_pushIntValue(myStackFrame,myValue.charValue);
			break;

		case FIELD_TYPE_SHORT:
			JVM_StackFrame_pushIntValue(myStackFrame,myValue.shortValue);
			break;


		case FIELD_TYPE_FLOAT:
			JVM_StackFrame_pushFloatValue(myStackFrame,myValue.floatValue);
			break;

		case FIELD_TYPE_INT:
			JVM_StackFrame_pushIntValue(myStackFrame,myValue.intValue);
			break;

		case FIELD_TYPE_ARRAY_REFERENCE:
		case FIELD_TYPE_CLASS_REFERENCE:
				JVM_StackFrame_pushReference(myStackFrame,myValue.reference);
			break;



		case FIELD_TYPE_LONG:
		case FIELD_TYPE_DOUBLE:
			JVM_StackFrame_pushLongValue(myStackFrame,myValue.longValue);

			break;


		default:
			return(STCD_UNKNOWN_FIELD_TYPE);
		}

	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_putstatic							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.5			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_putstatic()
{
	JVM_StackFrame_t * myStackFrame;

	uint8_t fieldType;
	uint16_t index;
	JVM_CP_Field_t * myFieldInfo;


	union data_value myValue;

	int16_t returnValue;
	JVM_Class_t *myClass;
	JVM_Field_t *myField;
	JVM_HandleNumber_t handleNumber;
	uint16_t dataOffset;


	index=JVM_Opcode_getCodeShort();

	myStackFrame=JVM_Opcode_getActiveStackFrame();

	returnValue=JVM_resolveFieldInfo(myStackFrame->currentCpTable,&myFieldInfo,index);
	if (returnValue!=STCD_OK)
		return(returnValue);


	myClass=myFieldInfo->classAddress;
	myField=myFieldInfo->fieldAddress;

	dataOffset=myField->dataOffset;
	handleNumber=myClass->staticDataHandle;

	fieldType=myField->fieldType;
	//TODO Check Type (fieldinfo_t <-> Field_t!!!
	// TODO check if really static

	switch(fieldType)
		{
		case FIELD_TYPE_BYTE:
		case FIELD_TYPE_BOOLEAN:
			myValue.byteValue=JVM_StackFrame_popIntValue(myStackFrame);
			break;

		case FIELD_TYPE_CHAR:
			myValue.charValue=JVM_StackFrame_popIntValue(myStackFrame);
			break;

		case FIELD_TYPE_SHORT:
			myValue.shortValue=JVM_StackFrame_popIntValue(myStackFrame);
			break;


		case FIELD_TYPE_INT:
			myValue.intValue=JVM_StackFrame_popIntValue(myStackFrame);
			break;

		case FIELD_TYPE_FLOAT:
			myValue.floatValue=JVM_StackFrame_popFloatValue(myStackFrame);
			break;

		case FIELD_TYPE_ARRAY_REFERENCE:
		case FIELD_TYPE_CLASS_REFERENCE:
			myValue.reference=JVM_StackFrame_popReference(myStackFrame);
			break;


		case FIELD_TYPE_LONG:
			myValue.longValue=JVM_StackFrame_popLongValue(myStackFrame);
			break;

		case FIELD_TYPE_DOUBLE:
			myValue.doubleValue=JVM_StackFrame_popDoubleValue(myStackFrame);
			break;



		default:
			return(STCD_UNKNOWN_FIELD_TYPE);
		}



	switch(fieldType)
		{
		case FIELD_TYPE_BYTE:
		case FIELD_TYPE_BOOLEAN:
			return(JVM_Handle_staticSetByte(handleNumber,dataOffset,myValue.byteValue));
			break;


		case FIELD_TYPE_CHAR:
			return(JVM_Handle_staticSetChar(handleNumber,dataOffset,myValue.charValue));
			break;

		case FIELD_TYPE_SHORT:
			return(JVM_Handle_staticSetShort(handleNumber,dataOffset,myValue.shortValue));
			break;


		case FIELD_TYPE_INT:
			return(JVM_Handle_staticSetInt(handleNumber,dataOffset,myValue.intValue));
			break;

		case FIELD_TYPE_ARRAY_REFERENCE:
		case FIELD_TYPE_CLASS_REFERENCE:
			return(JVM_Handle_staticSetReference(handleNumber,dataOffset,myValue.reference));
			break;


		case FIELD_TYPE_FLOAT:
			return(JVM_Handle_staticSetFloat(handleNumber,dataOffset,myValue.floatValue));
			break;


		case FIELD_TYPE_LONG:
			return(JVM_Handle_staticSetLong(handleNumber,dataOffset,myValue.longValue));
			break;

		case FIELD_TYPE_DOUBLE:
			return(JVM_Handle_staticSetDouble(handleNumber,dataOffset,myValue.doubleValue));
			break;


		default:
			return(STCD_UNKNOWN_FIELD_TYPE);
		}




	return(STCD_OK);
}


/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_getfield								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.5			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_getfield()
{
	JVM_StackFrame_t * myStackFrame;

	uint8_t fieldType;
	uint16_t index;
	JVM_CP_Field_t * myFieldInfo;


	union data_value myValue;

	int16_t returnValue;
	JVM_Class_t *myClass;
	JVM_Field_t *myField;
	JVM_HandleNumber_t handleNumber;
	uint16_t dataOffset;


	index=JVM_Opcode_getCodeShort();

	myStackFrame=JVM_Opcode_getActiveStackFrame();

	returnValue=JVM_resolveFieldInfo(myStackFrame->currentCpTable,&myFieldInfo,index);
	if (returnValue!=STCD_OK)
		return(returnValue);



	myClass=myFieldInfo->classAddress;
	myField=myFieldInfo->fieldAddress;

	dataOffset=myField->dataOffset;
	handleNumber=JVM_StackFrame_popReference(myStackFrame);


	fieldType=myField->fieldType;
	//TODO Check Type (fieldinfo_t <-> Field_t!!!
	// TODO check if not static



	uint16_t statusCode;

	switch(fieldType)
		{
		case FIELD_TYPE_BYTE:
		case FIELD_TYPE_BOOLEAN:
			statusCode=JVM_Handle_instanceGetByte(handleNumber,dataOffset,&myValue.byteValue);
				if(statusCode!=STCD_OK)
						return(statusCode);
			break;


		case FIELD_TYPE_CHAR:
			statusCode=JVM_Handle_instanceGetChar(handleNumber,dataOffset,&myValue.charValue);
				if(statusCode!=STCD_OK)
						return(statusCode);
			break;

		case FIELD_TYPE_SHORT:
			statusCode=JVM_Handle_instanceGetShort(handleNumber,dataOffset,&myValue.shortValue);
				if(statusCode!=STCD_OK)
						return(statusCode);
			break;


		case FIELD_TYPE_INT:
			JVM_Handle_instanceGetInt(handleNumber,dataOffset,&myValue.intValue);
			break;

		case FIELD_TYPE_ARRAY_REFERENCE:
		case FIELD_TYPE_CLASS_REFERENCE:

			JVM_Handle_instanceGetReference(handleNumber,dataOffset,&myValue.reference);
			//myValue.reference=reference;
			break;



		case FIELD_TYPE_FLOAT:
			JVM_Handle_instanceGetFloat(handleNumber,dataOffset,&myValue.floatValue);
			break;


		case FIELD_TYPE_LONG:
			JVM_Handle_instanceGetLong(handleNumber,dataOffset,&myValue.longValue);
			break;

		case FIELD_TYPE_DOUBLE:
			JVM_Handle_instanceGetDouble(handleNumber,dataOffset,&myValue.doubleValue);
			break;


		default:
			return(STCD_UNKNOWN_FIELD_TYPE);
		}



	return(JVM_Opcode_pushFieldValue(fieldType,myValue));

}
/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_putfield								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.2.5			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_putfield()
{
	JVM_StackFrame_t * myStackFrame;

	uint8_t fieldType;
	uint16_t index;
	JVM_CP_Field_t * myFieldInfo;


	union data_value myValue;

	int16_t returnValue;
	JVM_Class_t *myClass;
	JVM_Field_t *myField;
	JVM_HandleNumber_t handleNumber;
	uint16_t dataOffset;


	index=JVM_Opcode_getCodeShort();

	myStackFrame=JVM_Opcode_getActiveStackFrame();

	returnValue=JVM_resolveFieldInfo(myStackFrame->currentCpTable,&myFieldInfo,index);
	if (returnValue!=STCD_OK)
		return(returnValue);



	myClass=myFieldInfo->classAddress;
	myField=myFieldInfo->fieldAddress;

	dataOffset=myField->dataOffset;


	fieldType=myField->fieldType;
	//TODO Check Type (fieldinfo_t <-> Field_t!!!
	// TODO check if not static



	switch(fieldType)
		{
		case FIELD_TYPE_BYTE:
		case FIELD_TYPE_BOOLEAN:
			myValue.byteValue=JVM_StackFrame_popIntValue(myStackFrame);
			break;

		case FIELD_TYPE_CHAR:
			myValue.charValue=JVM_StackFrame_popIntValue(myStackFrame);
			break;

		case FIELD_TYPE_SHORT:
			myValue.shortValue=JVM_StackFrame_popIntValue(myStackFrame);
			break;

		case FIELD_TYPE_INT:
			myValue.intValue=JVM_StackFrame_popIntValue(myStackFrame);
			break;

		case FIELD_TYPE_FLOAT:
			myValue.floatValue=JVM_StackFrame_popFloatValue(myStackFrame);
			break;

		case FIELD_TYPE_ARRAY_REFERENCE:
		case FIELD_TYPE_CLASS_REFERENCE:
			myValue.reference=JVM_StackFrame_popReference(myStackFrame);
			break;


		case FIELD_TYPE_LONG:
			myValue.longValue=JVM_StackFrame_popLongValue(myStackFrame);
			break;

		case FIELD_TYPE_DOUBLE:
			myValue.doubleValue=JVM_StackFrame_popDoubleValue(myStackFrame);
			break;



		default:
			return(STCD_UNKNOWN_FIELD_TYPE);
		}



	handleNumber=JVM_StackFrame_popReference(myStackFrame);



	switch(fieldType)
		{
		case FIELD_TYPE_BYTE:
		case FIELD_TYPE_BOOLEAN:
			return(JVM_Handle_instanceSetByte(handleNumber,dataOffset,myValue.byteValue));
			break;


		case FIELD_TYPE_CHAR:
			return(JVM_Handle_instanceSetChar(handleNumber,dataOffset,myValue.charValue));
			break;

		case FIELD_TYPE_SHORT:
			return(JVM_Handle_instanceSetShort(handleNumber,dataOffset,myValue.shortValue));
			break;


		case FIELD_TYPE_INT:
			return(JVM_Handle_instanceSetInt(handleNumber,dataOffset,myValue.intValue));
			break;

		case FIELD_TYPE_ARRAY_REFERENCE:
		case FIELD_TYPE_CLASS_REFERENCE:
			return(JVM_Handle_instanceSetReference(handleNumber,dataOffset,myValue.reference));
			break;


		case FIELD_TYPE_FLOAT:
			return(JVM_Handle_instanceSetFloat(handleNumber,dataOffset,myValue.floatValue));
			break;


		case FIELD_TYPE_LONG:
			return(JVM_Handle_instanceSetLong(handleNumber,dataOffset,myValue.longValue));
			break;

		case FIELD_TYPE_DOUBLE:
			return(JVM_Handle_instanceSetDouble(handleNumber,dataOffset,myValue.doubleValue));
			break;


		default:
			return(STCD_UNKNOWN_FIELD_TYPE);
		}




	return(STCD_OK);
}


